import client.WsClient;
import com.alibaba.fastjson.JSONObject;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.DefaultPromise;
import io.netty.util.concurrent.Promise;
import lombok.extern.slf4j.Slf4j;
import model.Account;
import model.Message;
import org.apache.commons.lang3.StringUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.interactions.Actions;
import server.ThirdClient;
import util.Util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yujie
 * @createTime 2023/2/22 12:38
 * @description
 */
@Slf4j
public class selenuimchatgpt {


    public static void main(String[] args) throws InterruptedException {
        start();

    }

    public static void start() throws InterruptedException {
        List<Account> accounts = readAllAccount();
        accounts.forEach(account -> {
            new Thread(()->{
                ChromeDriver chromeDriver = configchrome(null, account);
                clickModal(chromeDriver);
                uploadDoc(account ,chromeDriver, 12, 0);
            }).start();
        });

    }

    private static void uploadDoc(Account account, ChromeDriver chromeDriver, int i, int j)  {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        WebElement bar = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div[2]/div[2]/div[2]/div/div"));
        WebElement element = bar.findElement(By.className("privilege-list"));
        List<WebElement> baritemList = element.findElements(By.className("privilege-item-container"));
        log.info("开始自动上传文档");
        if (i < 13){
            WebElement item = baritemList.get(i);
            Actions action = new Actions(chromeDriver);
            action.moveToElement(item).perform();
            item.click();
            //获取分页设置
            List<WebElement> numbers = null;
            try {
                WebElement page = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div[2]/div[4]/div/ul"));
                numbers = page.findElements(By.className("number"));
                if (j < 10){
                    //分页bug
                    for (WebElement number : numbers) {
                        if(StringUtils.equals(number.getText(), String.valueOf(j + 1))){
                            number.click();
                            break;
                        }
                    }
//                    WebElement number = numbers.get(j);
//                    number.click();
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    selectContentData(account, chromeDriver, i, j, 0, 0);
                    j++;
                    uploadDoc(account, chromeDriver, i, j);
                }else{
                    i++;
                    uploadDoc(account, chromeDriver, i, 0);
                }
            } catch (Exception e) {
                log.error("当前类目分页数据不存在，开始跳转, 坐标：{}，{}", i, j);
                uploadDoc(account, chromeDriver, i+1, j);
            }
        }

    }

    private static ChromeDriver configchrome(String str, Account account) {
        System.setProperty("webdriver.chrome.driver", "C:\\Users\\jack\\Downloads\\chromedriver_win32 (2)\\chromedriver.exe");
        Set<Cookie> cookieSet = new HashSet<>();
        String[] split = account.getCookie().split("; ");
        for (String cookie : split) {
            String[] split1 = cookie.split("=");
            Cookie cookie1 = new Cookie(split1[0], split1[1], "baidu.com","/", null);
            cookieSet.add(cookie1);
        }
        ChromeOptions options = new ChromeOptions();
        options.addArguments("--incognito");
        options.setExperimentalOption("excludeSwitches",  new String[]{"enable-automation"});
        options.addArguments("disable-blink-features=AutomationControlled");
        ChromeDriver chromeDriver = new ChromeDriver(options);
        chromeDriver.manage().window().maximize();         //最大化窗口

        chromeDriver.get("https://cuttlefish.baidu.com");
        cookieSet.forEach(cookie -> {
            chromeDriver.manage().addCookie(cookie);
        });
//        //点击登录
//        WebElement element = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/div[1]/div/div[2]/div[1]"));
//        WebElement a = element.findElement(By.tagName("a"));
//        Actions actions = new Actions(chromeDriver);
//        actions.moveToElement(a);
//        a.click();
//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//        WebElement username = chromeDriver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__userName\"]"));
//        username.sendKeys(account.getUsername());
//        WebElement password = chromeDriver.findElement(By.xpath("//*[@id=\"TANGRAM__PSP_11__password\"]"));
//        password.sendKeys(account.getPassword());
//        try {
//            Thread.sleep(500);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
//        password.sendKeys(Keys.ENTER);
//        try {
//            Thread.sleep(2000);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
        return chromeDriver;
    }

    private static List<Account> readAllAccount() {
        InputStream resourceAsStream = selenuimchatgpt.class.getClassLoader().getResourceAsStream("api.json");
        try {
            byte[] bytes = resourceAsStream.readAllBytes();
            String jsonString = new String(bytes);
            return JSONObject.parseArray(jsonString, Account.class);
        } catch (IOException e) {
            log.error("账号出错:{}",  e.getClass());
            throw new RuntimeException(e);
        }
    }

    private static void clickModal(ChromeDriver chromeDriver)  {
        chromeDriver.get("https://cuttlefish.baidu.com/ndecommtob/browse/index?_wkts_=" + new Date().getTime());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //点击空白区域
        Actions actions = new Actions(chromeDriver);
        actions.moveByOffset(100, 100).click().build().perform();

    }

    private static void selectContentData(Account account ,ChromeDriver chromeDriver, int i, int j, int cid, int ccid) throws InterruptedException {
        //获取content内容的所有数据
        //如果有模态框点击空白区域
        Actions actions1 = new Actions(chromeDriver);
        actions1.moveByOffset(0, 0).click().build().perform();
        //任务中心等待页面元素加载
        Thread.sleep(1000);
        try {
            WebElement wrapper = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div[2]/div[3]"));
            List<WebElement> content = wrapper.findElements(By.className("content"));
            //文本内容框
            if (cid < content.size()){
                WebElement contentItem = content.get(cid);
                try {
                    List<WebElement> elements = contentItem.findElements(By.className("doc-row"));
                    //任务集合
                    if (ccid < elements.size()){
                        //获取当前的元素标题
                        String text = contentItem.findElements(By.className("doc-row")).get(ccid).findElement(By.className("row-content")).findElement(By.className("title-line")).findElement(By.className("doc-title")).getText();
                        //开始尝试上传
                        WebElement uploadEle = contentItem.findElements(By.className("doc-row")).get(ccid).findElement(By.id("upload-doc"));
                        WebElement buttonClick = uploadEle.findElement(By.className("el-button"));
                        String disabled = buttonClick.getAttribute("disabled");
                        if((disabled == null || !StringUtils.equals(disabled, "true")) && text.length() >= 5){
                            try {
                                log.info("当前操作的账号是:{} ,当前点击的任务是:{}，坐标是{},{},{},{}",account.getUsername()  ,text, i, j, cid, ccid);
                                File wordFile = getWordFile(text);
                                if(Objects.nonNull(wordFile)){
                                    //进入详情页面提交文档
                                    Actions actions = new Actions(chromeDriver);
                                    //
                                    actions.moveToElement(buttonClick).perform();
                                    buttonClick.click();
                                    Runtime runtime = Runtime.getRuntime();
                                    log.info("上传的文件的地址:{}", wordFile.getAbsolutePath());
                                    runtime.exec("D:\\.work\\javastudy\\selenium-chatgpt\\src\\main\\resources\\upload.exe" + " "+ "chrome" + " " + wordFile.getAbsolutePath());
                                    Thread.sleep(7000);
                                    WebElement button = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div/div[3]/div[2]/button"));
                                    Actions actions2 = new Actions(chromeDriver);
                                    actions2.moveToElement(button).perform();
                                    button.click();
                                    Thread.sleep(3000);
                                    //返回列表页面
                                    try {
                                        chromeDriver.get("https://cuttlefish.baidu.com/ndecommtob/browse/index?_wkts_=" + new Date().getTime());
                                        Thread.sleep(7000);
                                        WebElement prompt = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[3]/div/div/div[3]/span/button"));
                                        prompt.click();
                                    } catch (Exception e) {
                                        log.error("创作中心页面没有检测到模态框");
                                    }

                                    //等待分页加载
                                    Thread.sleep(1000);
                                    //获取页头
                                    WebElement bar = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div[2]/div[2]/div[2]/div/div/div"));
                                    List<WebElement> baritemList = bar.findElements(By.className("privilege-item-container"));
                                    WebElement item = baritemList.get(i);
                                    Actions action = new Actions(chromeDriver);
                                    action.moveToElement(item).perform();
                                    item.click();
                                    //获取分页设置
                                    WebElement page = chromeDriver.findElement(By.xpath("//*[@id=\"app\"]/div[1]/section/main/div[1]/div[2]/div[4]/div/ul"));
                                    List<WebElement> numbers = page.findElements(By.className("number"));
                                    for (WebElement number : numbers) {
                                        if(StringUtils.equals(number.getText(), String.valueOf(j + 1))){
                                            number.click();
                                            break;
                                        }
                                    }
                                }
                            } catch (IOException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        ccid++;
                        selectContentData(account, chromeDriver, i, j, cid, ccid);
                    }else{
                        ccid = 0;
                        cid++;
                        selectContentData(account, chromeDriver, i, j, cid, 0);
                    }
                } catch (Exception e) {
                    log.error("第{}行 第{}列 数据拉取出现异常:{},{}", cid, ccid, e.getClass(), e);
                }
            }

        } catch (Exception e) {
            log.error("数据异常,{},{}", e.getClass(), e);
        }
    }


    private static Channel client = new WsClient().getClient();

    private static Lock lock = new ReentrantLock();

    public static File getWordFile(String queryName){
        main.license();
        lock.lock();
        try{
            if(Objects.nonNull(client)) {
                Message message = new Message("client_req", queryName+ " 尽量文字多一点");
                client.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(message)));
                DefaultPromise<Object> defaultPromise = new DefaultPromise<>(client.eventLoop());
                ThirdClient.map.put("WAIT_REP", defaultPromise);
                try {
                    //等待3分钟
                    defaultPromise.await(5, TimeUnit.MINUTES);
                } catch (InterruptedException e) {
                    log.error("响应异常：{}", e.getClass(), e);
                }
                String text = (String) defaultPromise.getNow();
//                Thread.sleep(60 * 1000);
                //openai 出现掉线
                if(StringUtils.isEmpty(text)){
                    //重新连接服务器
                    Message message1 = new Message("retry_req", queryName+ " 尽量文字多一点");
                    client.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(message1)));
                    //等待再次响应
                    log.info("等待重发的请求的响应");
                    ThirdClient.map.put("WAIT_RETRY_REP", defaultPromise);
                    //最长等待3分钟，如果3分钟结束说明请求被限制。等待一小时后再发送消息
                    defaultPromise.await(3, TimeUnit.MINUTES);
                    Object now1 = defaultPromise.getNow();
                    Promise<Object> waitRetryRep = ThirdClient.map.remove("WAIT_RETRY_REP");
                    if(Objects.isNull(now1) && Objects.nonNull(waitRetryRep)){
                        log.error("请求被限制，等待1个小时之后再请求");
                        Thread.sleep(60 * 60 * 1000);
                        client.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(message1)));
                        log.info("请求限制被解除后，等待重发的请求的响应");
                        ThirdClient.map.put("WAIT_RETRY_REP", defaultPromise);
                        //最长等待3分钟，如果3分钟结束说明请求被限制。等待一小时后再发送消息
                        defaultPromise.await();
                        Object now2 = defaultPromise.getNow();
                        Message message2 = (Message) now2;
                        return getFile(queryName, message2.getMsg());
                    }else{
                        Message now = (Message) now1;
                        log.info("收到转发的openai的重新响应:{}", now.getMsg());
                        String text1 = now.getMsg();
                        return getFile(queryName, text1);
                    }

                }else if(StringUtils.equals(text, "error")){
                    //chatgpt 请求超时，等待1小时
                    log.error("chatgpt 请求超时，等待1小时");
                    Thread.sleep(60 * 60 * 1000);
                    //等待完成之后重新尝试发请求
                    client.writeAndFlush(new TextWebSocketFrame(JSONObject.toJSONString(new Message("retry_req", message.getMsg()))));
                    ThirdClient.map.put("WAIT_REP", defaultPromise);
                    try {
                        //等待2分钟
                        defaultPromise.await(2, TimeUnit.MINUTES);
                    } catch (InterruptedException e) {
                        log.error("响应异常：{}", e.getClass(), e);
                    }
                    String text2 = (String) defaultPromise.getNow();
                    Thread.sleep(60 * 1000);
                    return getFile(queryName, text2);
                }else{
                    return getFile(queryName, text);
                }
            }else{
                log.error(queryName + "对应的文件生成失败");
                return null;
            }
        }catch (Exception e){
            log.info("出现异常:{},{}", e.getClass(), e);
            //提前解锁
            lock.unlock();
        }finally {
            lock.unlock();
        }
        return null;
    }

    private static File getFile(String queryName, String text1) {
        Map<String, Object> map = new HashMap<>();
        map.put("title", queryName);
        map.put("content", text1.trim().replaceAll("\\n\\n", "\\\n"));
        log.info("正在处理请求:"+ queryName);
        //防止文件名称过长导致windows脚本执行失败
        String name = queryName.replaceAll(" ", "").substring(0, 5);
        return Util.wordTextReplace(map, name);
    }

}
